package filter;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sourceforge.stripes.util.StringUtil;

import org.apache.commons.lang.StringUtils;

import actionbean.BaseActionBean;
import actionbean.LoginActionBean;

public class SecurityFilter implements Filter {

	private static boolean PROTECT_WEBSERVICE_WITH_ADMIN_PASSWORD = false;
	private static Set<String> adminUrls = new HashSet<String>();
	private static Set<String> studentUrls = new HashSet<String>();

	static {
		adminUrls.add(BaseActionBean.WEBSERVICE_PREFIX + "homepage");
		adminUrls.add(BaseActionBean.WEBSERVICE_PREFIX + "manual-round");
		adminUrls.add(BaseActionBean.WEBSERVICE_PREFIX + "manual-bootstrap");

		studentUrls.add(BaseActionBean.URI_FOR_BIDS);
		studentUrls.add(BaseActionBean.URI_FOR_BOOKMARKS);
		studentUrls.add(BaseActionBean.URI_FOR_COURSES);
		studentUrls.add(BaseActionBean.URI_FOR_TIMETABLE);
	}

	private boolean isStudentLoggedIn(HttpServletRequest request) {
		String loggedInUserId = (String) request.getSession().getAttribute(
				"loggedInUserId");
		return loggedInUserId != null
				&& !loggedInUserId.equals(LoginActionBean.ADMIN_USERID);
	}

	private boolean isAdminLoggedIn(HttpServletRequest request) {
		String loggedInUserId = (String) request.getSession().getAttribute(
				"loggedInUserId");
		return loggedInUserId != null
				&& loggedInUserId.equals(LoginActionBean.ADMIN_USERID);
	}

	/** Does nothing. */
	public void init(FilterConfig filterConfig) throws ServletException {
	}

	public void doFilter(ServletRequest servletRequest,
			ServletResponse servletResponse, FilterChain filterChain)
			throws IOException, ServletException {

		HttpServletRequest request = (HttpServletRequest) servletRequest;
		HttpServletResponse response = (HttpServletResponse) servletResponse;

		if (hasUserAccessToResource(request)) {
			filterChain.doFilter(request, response);
		} else {
			redirectToLoginPage(request, response);
		}
	}

	private String getTargetUrl(HttpServletRequest request) {
		String servletPath = request.getServletPath();
		String requestUri = request.getRequestURI();
		if (requestUri.indexOf(servletPath) > -1) {
			return requestUri.substring(requestUri.indexOf(servletPath),
					requestUri.length());
		} else {
			return servletPath;
		}

	}

	private boolean isAdminResource(HttpServletRequest request) {
		String resource = StringUtils.removeStart(request.getRequestURI(),
				request.getContextPath());
		if (PROTECT_WEBSERVICE_WITH_ADMIN_PASSWORD) {
			return resource.startsWith(BaseActionBean.WEBSERVICE_PREFIX);
		} else {
			/*
			 * Obtain string before the third slash.
			 */
			String adminResource = StringUtils.removeStart(resource,
					BaseActionBean.WEBSERVICE_PREFIX);
			adminResource = StringUtils.substringBefore(adminResource, "/");
			adminResource = BaseActionBean.WEBSERVICE_PREFIX + adminResource;
			return adminUrls.contains(adminResource);
		}
	}

	private boolean isStudentResource(String resource) {
		return resource.startsWith(BaseActionBean.STUDENT_PREFIX)
				|| studentUrls.contains(resource + "/");
	}

	private boolean hasUserAccessToResource(HttpServletRequest request) {
		String resource = request.getServletPath();

		if (resource.equals(BaseActionBean.URI_FOR_ADMIN_LOGIN)
				|| resource.equals(BaseActionBean.URI_FOR_STUDENT_LOGIN)
				|| resource.equals(BaseActionBean.URI_FOR_LOGOUT)) {
			return true;
		}
		if (isAdminResource(request) && !isAdminLoggedIn(request)) {
			return false;
		} else if (isStudentResource(resource) && !isStudentLoggedIn(request)) {
			return false;
		}

		return true;
	}

	/** Does nothing. */
	public void destroy() {
	}

	private void redirectToLoginPage(HttpServletRequest request,
			HttpServletResponse response) throws IOException {
		String targetUrl = StringUtil.urlEncode(getTargetUrl(request));
		String loginUri = BaseActionBean.URI_FOR_STUDENT_LOGIN;
		if (isAdminResource(request)) {
			loginUri = BaseActionBean.URI_FOR_ADMIN_LOGIN;
		}
		response.sendRedirect(request.getContextPath() + loginUri
				+ "?targetUrl=" + targetUrl);
	}
}
